package org.example.study11;

import java.util.concurrent.locks.ReentrantLock;

public class ThreadSafeCounterDemo {
    public static void main(String[] args) throws InterruptedException {
        // 创建线程安全的计数器实例
        ThreadSafeCounter counter = new ThreadSafeCounter();

        // 创建两个线程同时进行累加操作
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increment();  // 线程t1执行5万次递增
            }
            System.out.println("线程t1完成累加");
        }, "Increment-Thread-1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increment();  // 线程t2执行5万次递增
            }
            System.out.println("线程t2完成累加");
        }, "Increment-Thread-2");

        // 记录开始时间
        long startTime = System.currentTimeMillis();

        // 启动两个线程
        t1.start();
        t2.start();

        // 等待两个线程执行完成
        t1.join();
        t2.join();

        // 计算执行时间
        long endTime = System.currentTimeMillis();

        // 输出最终结果，正确情况下应该是100000
        System.out.println("最终计数结果: " + counter.getCount());
        System.out.println("总执行时间: " + (endTime - startTime) + "ms");
    }
}

/**
 * 线程安全计数器类
 * 使用ReentrantLock保护共享变量的并发访问
 */
class ThreadSafeCounter {
    // 共享计数器变量，volatile保证可见性但不保证原子性
    private volatile int count = 0;
    // 创建ReentrantLock实例用于同步控制
    private final ReentrantLock lock = new ReentrantLock();

    /**
     * 线程安全的递增方法
     * 使用锁保证count++操作的原子性
     */
    public void increment() {
        lock.lock();        // 加锁，保证同一时刻只有一个线程能执行临界区代码
        try {
            count++;        // 临界区操作：读取-修改-写入，需要保证原子性
            // 这个操作实际上包含三个步骤：
            // 1. 读取count当前值到线程工作内存
            // 2. 将值加1
            // 3. 将新值写回主内存
            // 如果没有锁保护，两个线程可能同时读取到相同的值，导致少加
        } finally {
            lock.unlock();  // 在finally块中释放锁，确保异常情况下锁也能被释放
        }
    }

    /**
     * 获取当前计数值
     * 由于count是volatile的，读操作本身是线程安全的
     */
    public int getCount() {
        return count;
    }
}

/*运行结果可能是
线程t2完成累加
线程t1完成累加
最终计数结果: 100000
总执行时间: 15ms
*/